package com.xbongbong.saas.model.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.xbongbong.aiassistant.domain.entity.AiProductEntity;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.ext.ConditionsEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.pojo.dto.DeleteDTO;
import com.xbongbong.paas.elasticsearch.pojo.dto.InsertDTO;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.UnitItemPoJo;
import com.xbongbong.paas.help.FormDataHelp;
import com.xbongbong.paas.model.PaasAppModel;
import com.xbongbong.paas.pojo.MultiUnitPricePoJo;
import com.xbongbong.paas.pojo.ProductFieldPojo;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.EnableApiCallBack;
import com.xbongbong.paas.util.DataUtil;
import com.xbongbong.paas.util.ItemUtil;
import com.xbongbong.pro.businessdata.pojo.dto.FormatExplainDTO;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.constant.SymbolConstant;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.enums.ApiCallBackEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.form.pojo.dto.ChildProductDTO;
import com.xbongbong.pro.formdata.pojo.dto.SaasAnalysisDataDTO;
import com.xbongbong.pro.product.pojo.ProductPriceSetPOJO;
import com.xbongbong.pro.product.pojo.dto.FilterAttrOnOffJXCDTO;
import com.xbongbong.pro.product.pojo.vo.FilterAttrOnOffJXCVO;
import com.xbongbong.pro.statistic.pojo.vo.ProductInfoVO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.constant.TabConstant;
import com.xbongbong.saas.domain.dao.ProductDao;
import com.xbongbong.saas.domain.dao.SmartReplenishmentDao;
import com.xbongbong.saas.domain.entity.ProductStockUpdateEntity;
import com.xbongbong.saas.domain.entity.ext.CustomerEntityExt;
import com.xbongbong.saas.domain.entity.ext.ProductEntityExt;
import com.xbongbong.saas.enums.OperatePageEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.help.SaasFormHelp;
import com.xbongbong.saas.help.ShowFormatHelp;
import com.xbongbong.saas.model.CustomerModel;
import com.xbongbong.saas.model.CustomerUserModel;
import com.xbongbong.saas.model.PaasFormSubDataModel;
import com.xbongbong.saas.model.ProductModel;
import com.xbongbong.saas.model.ProductSubDataModel;
import com.xbongbong.saas.service.toolbox.handle.WebCommonDataValueMatchHandle;
import com.xbongbong.saas.service.toolbox.handle.WebListDataValueMatchHandle;
import com.xbongbong.saas.service.toolbox.help.AttrDecimalPrecisionHelper;
import com.xbongbong.saas.util.StandardizeDataUtil;
import com.xbongbong.saas.util.StringStreamUtil;
import com.xbongbong.sys.domain.entity.PriceProductSetEntity;
import com.xbongbong.sys.domain.entity.PriceSetEntity;
import com.xbongbong.sys.model.CompanyConfigModel;
import com.xbongbong.sys.model.PriceProductSetModel;
import com.xbongbong.sys.model.PriceSetModel;
import org.apache.commons.collections4.CollectionUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getDoubleOrDefaultFromFormData;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;
import static org.elasticsearch.index.query.QueryBuilders.wildcardQuery;

/**
 * @author Jian.Wang
 * @date  2019-01-28 9:11
 **/
@Service("ProductModel")
public class ProductModelImpl implements ProductModel{

    @Resource
    private ProductDao productDao;
    @Resource
    private PaasEsModel paasEsModel;
    @Resource
    private EsHelper esHelper;
    @Resource
    private PaasFormSubDataModel paasFormSubDataModel;
    @Resource
    private ProductSubDataModel productSubDataModel;
    @Resource
    private SaasFormHelp saasFormHelp;
    @Resource
    private CompanyConfigModel companyConfigModel;
    @Resource
    private PaasAppModel paasAppModel;
    @Resource
    private ShowFormatHelp showFormatHelp;
    @Resource
    private CustomerModel customerModel;
    @Resource
    private PriceSetModel priceSetModel;
    @Resource
    private WebCommonDataValueMatchHandle webCommonDataValueMatchHandle;
    @Resource
    private WebListDataValueMatchHandle webListDataValueMatchHandle;
    @Resource
    private PriceProductSetModel priceProductSetModel;
    @Resource
    private SmartReplenishmentDao smartReplenishmentDao;
    @Resource
    private CustomerUserModel customerUserModel;

    private static final List<String> productFilterAttrList = Arrays.asList(ProductEnum.WAREHOUSE.getAttr(), ProductEnum.WAREHOUSE_INFO.getAttr(), ProductEnum.STOCK_INFO.getAttr()
            , ProductEnum.STOCK_NOTIFY.getAttr(), ProductEnum.IS_NOTIFY.getAttr(), ProductEnum.SUPPLIER.getAttr(), ProductEnum.ASSOCIATED_INFO.getAttr()
            ,ProductEnum.BATCH_SHELF_LIFE_MANAGEMENT.getAttr(), ProductEnum.ENABLE_BATCH_SHELF_LIFE.getAttr(), ProductEnum.SHELF_LIFE_DAYS.getAttr(), ProductEnum.EXPIRATION_ALERT_DAYS.getAttr()
            ,ProductEnum.SERIAL_NUMBER_MANAGEMENT.getAttr(), ProductEnum.ENABLE_SERIAL_NUMBER.getAttr());
    private static final List<String> noBatchSeqAttrList = Arrays.asList(ProductEnum.WAREHOUSE.getAttr(), ProductEnum.WAREHOUSE_INFO.getAttr(), ProductEnum.STOCK_INFO.getAttr()
            , ProductEnum.STOCK_NOTIFY.getAttr(), ProductEnum.IS_NOTIFY.getAttr(), ProductEnum.SUPPLIER.getAttr(), ProductEnum.ASSOCIATED_INFO.getAttr());
    private static final List<String> batchAttrList = Arrays.asList(ProductEnum.BATCH_SHELF_LIFE_MANAGEMENT.getAttr(), ProductEnum.ENABLE_BATCH_SHELF_LIFE.getAttr(), ProductEnum.SHELF_LIFE_DAYS.getAttr(), ProductEnum.EXPIRATION_ALERT_DAYS.getAttr());
    private static final List<String> seqAttrList = Arrays.asList(ProductEnum.SERIAL_NUMBER_MANAGEMENT.getAttr(), ProductEnum.ENABLE_SERIAL_NUMBER.getAttr());
    @Resource
    private FormDataHelp formDataHelp;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.PRODUCT, operateTypeEnum = OperateTypeEnum.NEW, isBatch = true)
    public Integer insertBatch(List<ProductEntityExt> productList) throws XbbException{
        for (ProductEntityExt entityExt : productList) {
            if (Objects.isNull(entityExt.getAddTime())) {
                entityExt.setAddTime(DateTimeUtil.getInt());
            }
            if (Objects.isNull(entityExt.getUpdateTime())) {
                entityExt.setUpdateTime(DateTimeUtil.getInt());
            }
            paasFormSubDataModel.transferSubForm(entityExt, IndexTypeEnum.IDX_SAAS_PRODUCT_SUB);
        }
        StandardizeDataUtil.standardize4EntityList(productList);
        Integer returnId = productDao.insertBatch(productList);
        //ES数据插入
        List<InsertDTO> insertList = new ArrayList<>();
        for (ProductEntityExt entity : productList) {
            PaasFormDataEntity paasFormDataEntity = new PaasFormDataEntity();
            BeanUtil.copyProperties(entity, paasFormDataEntity);
            JSONObject data = paasFormDataEntity.getData();
            // 产品简介不入es
            data.put(ProductEnum.INSTRUCTION.getAttr(),"");
            paasFormDataEntity.setData(data);
            InsertDTO insertDTO = paasEsModel.getSaveDTO(paasFormDataEntity, IndexTypeEnum.IDX_SAAS_PRODUCT);
            insertDTO.setWaitUntil(WriteRequest.RefreshPolicy.NONE);
            insertDTO.getSource().remove("num");
            insertDTO.getSource().remove("cost");
            insertDTO.getSource().remove("totalCost");
            insertList.add(insertDTO);
        }
        paasEsModel.insertBatch(insertList);

        paasFormSubDataModel.insertBatchSubFormData(productList, IndexTypeEnum.IDX_SAAS_PRODUCT_SUB);
        return returnId;
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.PRODUCT, operateTypeEnum = OperateTypeEnum.NEW)
    public Integer insert(ProductEntityExt entity) throws XbbException {
        long now = DateTimeUtil.getInt();
        entity.setAddTime(now);
        entity.setUpdateTime(now);

        paasFormSubDataModel.transferSubForm(entity, IndexTypeEnum.IDX_SAAS_PRODUCT_SUB);
        StringStreamUtil.validateDataSize(JSON.toJSONString(entity.getData()));
        StandardizeDataUtil.standardizeNotString(entity);
        Integer insertId = productDao.insert(entity);
        PaasFormDataEntity paasFormDataEntity = new PaasFormDataEntity();
        BeanUtil.copyProperties(entity, paasFormDataEntity);
        JSONObject data = paasFormDataEntity.getData();
        // 产品简介不入es
        data.put(ProductEnum.INSTRUCTION.getAttr(),"");
        paasFormDataEntity.setData(data);
        InsertDTO insertDTO = paasEsModel.getSaveDTO(paasFormDataEntity, IndexTypeEnum.IDX_SAAS_PRODUCT);
        insertDTO.getSource().remove("num");
        insertDTO.getSource().remove("cost");
        insertDTO.getSource().remove("totalCost");
        paasEsModel.insert(insertDTO);

        paasFormSubDataModel.insertSubFormData(entity, IndexTypeEnum.IDX_SAAS_PRODUCT_SUB);
        return insertId;
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.PRODUCT, operateTypeEnum = OperateTypeEnum.EDIT)
    public Integer update(ProductEntityExt entity) throws XbbException {
        long now = DateTimeUtil.getInt();
        entity.setUpdateTime(now);

        paasFormSubDataModel.transferSubForm(entity, IndexTypeEnum.IDX_SAAS_PRODUCT_SUB);
        StringStreamUtil.validateDataSize(JSON.toJSONString(entity.getData()));
        StandardizeDataUtil.standardizeNotString(entity);
        Integer updateId = productDao.update(entity);
        PaasFormDataEntity paasFormDataEntity = new PaasFormDataEntity();
        BeanUtil.copyProperties(entity, paasFormDataEntity, false);
        JSONObject data = paasFormDataEntity.getData();
        // 产品简介不入es
        data.put(ProductEnum.INSTRUCTION.getAttr(),"");
        paasFormDataEntity.setData(data);
        InsertDTO insertDTO = paasEsModel.getSaveDTO(paasFormDataEntity, IndexTypeEnum.IDX_SAAS_PRODUCT);
        insertDTO.getSource().remove("num");
        insertDTO.getSource().remove("cost");
        insertDTO.getSource().remove("totalCost");
        paasEsModel.update(insertDTO);

        paasFormSubDataModel.updateSubFormData(entity, IndexTypeEnum.IDX_SAAS_PRODUCT_SUB);
        if (Objects.nonNull(entity.getSubFormData()) && !entity.getSubFormData().isEmpty()) {
            entity.getData().putAll(entity.getSubFormData());
        }
        return updateId;
    }

    @Override
    public Integer save(ProductEntityExt entity) throws XbbException {
        Long id = entity.getId();
        if (id == null || id == 0) {
            // 新建
            return insert(entity);
        } else {
            // 更新
            return update(entity);
        }
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.PRODUCT, operateTypeEnum = OperateTypeEnum.DELETE)
    public Integer deleteByKey(Long key, String corpid) throws XbbException {
        // 更新es
        DeleteDTO deleteDTO = new DeleteDTO();
        deleteDTO.setEsId(corpid + "_" + key);
        deleteDTO.setIndexTypeEnum(IndexTypeEnum.IDX_SAAS_PRODUCT);
        paasEsModel.delete(deleteDTO);

        paasFormSubDataModel.deleteByDataId(key, corpid, IndexTypeEnum.IDX_SAAS_PRODUCT_SUB);
        return productDao.deleteByKey(key, corpid);
    }

    @Override
    public List<ProductEntityExt> findEntitys(Map<String, Object> param) {
        List<ProductEntityExt> entitys = productDao.findEntitys(param);
        Object corpid = param.get(ParameterConstant.CORPID);
        if (Objects.nonNull(corpid)) {
            paasFormSubDataModel.findSubEntity(corpid.toString(), entitys, IndexTypeEnum.IDX_SAAS_PRODUCT_SUB);
        }
        return entitys;
    }

    @Override
    public List<PaasFormDataEntityExt> findEntitysByPaas(Map<String, Object> param) {
        return productDao.findEntitysByPaas(param);
    }

    @Override
    public Integer getEntitysCount(Map<String, Object> param) {
        return productDao.getEntitysCount(param);
    }

    @Override
    public List findEntitysWithoutSub(Map<String, Object> param) {
        return productDao.findEntitys(param);
    }

    @Override
    public ProductEntityExt getByKey(Long key, String corpid) {
        ProductEntityExt entityExt = productDao.getByKey(key, corpid);
        paasFormSubDataModel.findSubEntity(corpid, Collections.singletonList(entityExt), IndexTypeEnum.IDX_SAAS_PRODUCT_SUB);
        return entityExt;
    }

    /**
     * 过滤产品规格中 规格名称和规格值里面的双引号
     *
     * @param spec 要过滤的规格
     * @author GuoJun.HU
     * @since 3.14
     * 创建时间 2018/1/27 19:00
     */
    @Override
    public String filterProductSpecDoubleQuotes(String spec) {
        if (StringUtil.isEmpty(spec)) {
            return "{}";
        }
        JSONObject specObj;
        try {
            specObj = JSON.parseObject(spec, JSONObject.class, Feature.OrderedField);
        } catch (Exception e) {
            specObj = new JSONObject();
        }
        if (specObj == null || specObj.isEmpty()) {
            return "{}";
        }

        JSONObject specification = new JSONObject(new LinkedHashMap<>());
        Set<String> keySet = specObj.keySet();
        for (String key : keySet) {
            String value = specObj.getString(key);
            specification.put(StringUtil.filterDoubleQuotes(key), StringUtil.filterDoubleQuotes(value));
        }

        return specification.toJSONString();
    }
    /**
     * 过滤产品规格中 规格名称和规格值里面的双引号过滤数组形式
     *
     * @param spec 要过滤的规格
     * @author JYH
     * 创建时间 2019/11/25 15:25
     */
    @Override
    public String filterProductSpecDoubleQuotesWithArray(String spec) {
        if (StringUtil.isEmpty(spec)) {
            return "[]";
        }
        JSONArray specObj;
        try {
            specObj = JSON.parseArray(spec);
        } catch (Exception e) {
            specObj = new JSONArray();
        }
        if (specObj == null || specObj.isEmpty()) {
            return "[]";
        }

        JSONArray specification = new JSONArray();

        for (Object o : specObj) {
            String value=o.toString();
            specification.add(StringUtil.filterDoubleQuotes(value));
        }

        return specification.toJSONString();
    }

    /**
     * 通过id列表获取产品并构建id和entity的对应关系
     *
     * @param corpid      公司id
     * @param productIdIn 产品id列表
     * @param del         删除标志
     * @author Jian.Wang
     * @date 2018/2/21 17:26
     */
    @Override
    public Map<Long, ProductEntityExt> getProductMapByIdIn(String corpid, List<Long> productIdIn, Integer del) {
        List<ProductEntityExt> productList = getProductListByIdIn(corpid, productIdIn, del);
        Map<Long, ProductEntityExt> productMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (ProductEntityExt product : productList) {
            productMap.put(product.getId(), product);
        }
        return productMap;
    }

    /**
     * 通过id列表获取产品并构建id和entity的对应关系
     *
     * @param corpid      公司id
     * @param productIdIn 产品id列表
     * @param del         删除标志
     * @throws XbbException
     * @author long.rao
     * @date 2019-07-15 15:58
     */
    @Override
    public Map<Long, ProductEntityExt> getProductMapByIds(String corpid, List<Long> productIdIn, Integer del, List<String> fieldList) throws XbbException{
        List<ProductEntityExt> productList = getProductListByIds(corpid, productIdIn, del, fieldList);
        Map<Long, ProductEntityExt> productMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (ProductEntityExt product : productList) {
            productMap.put(product.getId(), product);
        }
        return productMap;
    }

    @Override
    public Map<Long, ProductInfoVO> getProductMapByIdIn4Es(List<ProductInfoVO> products) {
        //从es查询 getProductListByIdInEs(corpid, productIdIn, del);
        //产品id--产品信息
        Map<Long, ProductInfoVO> productMap = new HashMap<>(products.size());
        for (ProductInfoVO infoVo : products) {
            productMap.put(infoVo.getId(), infoVo);
        }
        return productMap;
    }

    @Override
    public Map<Long, ProductInfoVO> getParentProductListByIdIn4Es(String corpid, List<ProductInfoVO> products, Integer del) throws XbbException {
        //从es查询 getProductListByIdInEs(corpid, productIdIn, del);
        Set<Long> parentIdIn = new HashSet<>();
        String parentIdAttr = ProductEnum.PARENT_ID.getAttr();
        for (ProductInfoVO child : products) {
            JSONObject data = child.getData();
            if (data == null) {
                continue;
            }
            Long parentId = data.getLong(parentIdAttr);
            if (parentId == null) {
                continue;
            }
            child.setParentId(parentId);
            parentIdIn.add(parentId);
        }
        //查出该批产品（productIdIn）对应的父产品（parentIdIn）信息列表
        List<ProductInfoVO> parentList = getProductListByIdInEs(corpid, parentIdIn, del);
        //父分类id--父分类实体
        Map<Long, ProductInfoVO> parentMap = new HashMap<>(parentList.size());
        for (ProductInfoVO parent : parentList) {
            JSONObject data = parent.getData();
            if (data == null) {
                parent.setData(new JSONObject());
            }
            parentMap.put(parent.getId(), parent);
        }
        //产品id--产品父分类实体
        Map<Long, ProductInfoVO> childMap = new HashMap<>(products.size());
        for (ProductInfoVO child : products) {
            Long parentId = child.getParentId();
            if (!parentMap.containsKey(parentId)) {
                continue;
            }
            childMap.put(child.getId(), parentMap.get(parentId));
        }
        return childMap;
    }

    /**
     * 通过id列表获取产品
     *
     * @param corpid      公司id
     * @param productIdIn 产品id列表
     * @param del         删除标志
     * @author Jian.Wang
     * @date 2018/2/21 17:26
     */
    @Override
    public List<ProductEntityExt> getProductListByIdIn(String corpid, List<Long> productIdIn, Integer del) {
        if (productIdIn == null || productIdIn.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put("corpid", corpid);
        modelMap.put("productIdIn", productIdIn);
        if (del != null) {
            modelMap.put("del", del);
        }
        return findEntitys(modelMap);
    }

    /**
     * 通过id列表获取产品
     *
     * @param corpid      公司id
     * @param productIdIn 产品id列表
     * @param del         删除标志
     * @param fieldList
     * @author long.rao
     * @date 2019-08-16 13:51
     */
    @Override
    public List<ProductEntityExt> getProductListByIds(String corpid, List<Long> productIdIn, Integer del, List<String> fieldList) throws XbbException{
        if (productIdIn == null || productIdIn.isEmpty()) {
            return new ArrayList<>();
        }
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termsQuery("dataId", productIdIn));
        if (del != null) {
            boolQueryBuilder.filter(termQuery("del", del));
        }
        XbbAggregatedPage<ProductEntityExt> byPage = esHelper.findByPage(IndexTypeEnum.IDX_SAAS_PRODUCT, boolQueryBuilder, ProductEntityExt.class, fieldList, 0, productIdIn.size(), null);
        return byPage.getContent();
    }
    /**
     * 通过产品id集合和模糊搜索的产品名称去查询符合条件的id集合(购物车列表用到)
     * @param corpid      公司id
     * @param productIdIn 产品id列表
     * @param del         删除标志
     * @param fieldList   查询的属性
     * @param productName 商品名称
     * @throws XbbException
     * @author weiming
     * @date 2021-02-22 13:59
     */
    @Override
    public List<Long> getProductIds(String corpid, List<Long> productIdIn, Integer del, List<String> fieldList, String productName) throws XbbException {
        List<PaasFormDataEntityExt> productList = getProductsByIds(corpid, productIdIn, del, fieldList, productName);
        List<Long> productIds = new ArrayList<>();
        for (PaasFormDataEntityExt paasFormDataEntityExt : productList) {
            productIds.add(paasFormDataEntityExt.getDataId());
        }
        return productIds;
    }
    /**
     * 通过id列表获取产品
     *
     * @param corpid      公司id
     * @param productIdIn 产品id列表
     * @param del         删除标志
     * @param fieldList
     * @author weiming
     * @date 2020-12-29
     */
    @Override
    public List<PaasFormDataEntityExt> getProductsByIds(String corpid, List<Long> productIdIn, Integer del, List<String> fieldList, String productName) throws XbbException{
        if (productIdIn == null || productIdIn.isEmpty()) {
            return new ArrayList<>();
        }
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termsQuery("dataId", productIdIn));
        if (del != null) {
            boolQueryBuilder.filter(termQuery("del", del));
        }
        if (productName != null){
            //根据productName模糊查询商品名称
            boolQueryBuilder.must(wildcardQuery(ProductEnum.getEsAttr4Keyword(ProductEnum.NAME), "*"+productName+"*"));
        }
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,IndexTypeEnum.IDX_SAAS_PRODUCT.getType()));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(boolQueryBuilder);
        List<PaasFormDataEntityExt> entityExts = paasEsModel.list(sourceBuilder, IndexTypeEnum.IDX_SAAS_PRODUCT, Arrays.asList(StringConstant.JSON_DATA), null, 300);
        return entityExts;
    }

    @Override
    public List<ProductInfoVO> getProductListByIdInEs(String corpid, Collection<Long> productIdIn, Integer del) throws XbbException {
        if (productIdIn == null || productIdIn.isEmpty()) {
            return new ArrayList<>();
        }
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termsQuery("dataId", productIdIn));
        if (del != null) {
            boolQueryBuilder.filter(termQuery("del", del));
        }

        XbbAggregatedPage<ProductInfoVO> byPage = esHelper.findByPage(IndexTypeEnum.IDX_SAAS_PRODUCT, boolQueryBuilder, ProductInfoVO.class, null, 0, productIdIn.size(), null);
        return byPage.getContent();
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.PRODUCT, operateTypeEnum = OperateTypeEnum.DELETE, isBatch = true)
    public Integer deleteBatch(List<Long> list, String corpid, Integer del) throws XbbException {
        Integer integer = productDao.deleteByIdIn(corpid, list);
        //ES根据id批量设置del=1
        paasEsModel.deleteBatch(list, corpid, DelEnum.DELETE.getDel(), IndexTypeEnum.IDX_SAAS_PRODUCT);

        paasFormSubDataModel.deleteBatchByDataId(list, corpid, IndexTypeEnum.IDX_SAAS_PRODUCT_SUB, DelEnum.DELETE_SUBFORM);
        return integer;
    }

    @Override
    public Map<String, Map<Long, ProductEntityExt>> getProductWithParentMapByIdIn(String corpid, List<Long> idIn, List<String> fieldList) throws XbbException {
        Map<String, Map<Long, ProductEntityExt>> resultMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, ProductEntityExt> productMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, ProductEntityExt> parentProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (corpid == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028);
        }
        if (idIn == null || idIn.isEmpty()) {
            resultMap.put(StringConstant.PRODUCT_MAP, productMap);
            resultMap.put(StringConstant.PARENT_PRODUCT_MAP, parentProductMap);
            return resultMap;
        }
        if (idIn.size() > 0) {
            //先获取子产品
            BoolQueryBuilder boolQueryBuilder = boolQuery();
            boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
            boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
            boolQueryBuilder.filter(termsQuery(FieldTypeEnum.DATAID.getAlias(), idIn));
            boolQueryBuilder.mustNot(termQuery(ProductEnum.getEsAttr4Keyword(ProductEnum.PARENT_ID),0));
            List<ProductEntityExt> productEntityExts = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PRODUCT,boolQueryBuilder,ProductEntityExt.class, fieldList);
            paasFormSubDataModel.findSubEntity(corpid, productEntityExts, IndexTypeEnum.IDX_SAAS_PRODUCT_SUB);

            List<Long> parentIdIn = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            parentIdIn.add(-1L);
            if (productEntityExts != null) {
                for (ProductEntityExt entity : productEntityExts) {
                    productMap.put(entity.getId(), entity);
                    parentIdIn.add(entity.getData().getLong(ProductEnum.PARENT_ID.getAttr()));
                }
            }
            // 获取保存产品的父产品，用来保存编号
            boolQueryBuilder = boolQuery();
            boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
            boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
            boolQueryBuilder.filter(termsQuery(FieldTypeEnum.DATAID.getAlias(), parentIdIn));
            List<ProductEntityExt> parentProduct = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PRODUCT,boolQueryBuilder,ProductEntityExt.class, fieldList);
            paasFormSubDataModel.findSubEntity(corpid, parentProduct, IndexTypeEnum.IDX_SAAS_PRODUCT_SUB);

            if (!parentProduct.isEmpty()) {
                parentProduct.forEach(item -> parentProductMap.put(item.getId(), item));
            }
        }
        resultMap.put(StringConstant.PRODUCT_MAP, productMap);
        resultMap.put(StringConstant.PARENT_PRODUCT_MAP, parentProductMap);
        return resultMap;
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.PRODUCT, operateTypeEnum = OperateTypeEnum.EDIT, isBatch = true)
    public Integer updateBatch(List<UpdateDataEntity> list, String corpid) throws XbbException {
        //1. 先拿到子表单数据
        List<UpdateDataEntity> subList = DataUtil.getUpdateSubDataList(list);
        // 2. 主表删掉子表单数据
        DataUtil.removeSubDataInData(list);
        Integer integer = 0;
        if (CollectionsUtil.isNotEmpty(list)) {
            StandardizeDataUtil.standardizeList(list);
            integer = productDao.updateBatch(list, corpid);
            // 将产品简介的es数据置空
            setInstructionEmpty(list);
            paasEsModel.updateBatchMuchField(list, IndexTypeEnum.IDX_SAAS_PRODUCT);
        }
        if (!subList.isEmpty()) {
            productSubDataModel.updateBatch(subList, corpid);
        }
        return integer;
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.PRODUCT, operateTypeEnum = OperateTypeEnum.EDIT, isBatch = true)
    public Integer updateBatchImmediately(List<UpdateDataEntity> list, String corpid) throws XbbException {
        //1. 先拿到子表单数据
        List<UpdateDataEntity> subList = DataUtil.getUpdateSubDataList(list);
        // 2. 主表删掉子表单数据
        DataUtil.removeSubDataInData(list);
        Integer integer = 0;
        if (CollectionsUtil.isNotEmpty(list)) {
            StandardizeDataUtil.standardizeList(list);
            integer = productDao.updateBatch(list, corpid);
            // 将产品简介的es数据置空
            setInstructionEmpty(list);
            paasEsModel.updateBatchMuchField(list, IndexTypeEnum.IDX_SAAS_PRODUCT, WriteRequest.RefreshPolicy.NONE);
        }
        if (!subList.isEmpty()) {
            productSubDataModel.updateBatch(subList, corpid);
        }
        return integer;
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.PRODUCT, operateTypeEnum = OperateTypeEnum.EDIT, isBatch = true)
    public Integer updateBatch(List<UpdateDataEntity> list, String corpid, WriteRequest.RefreshPolicy refreshPolicy) throws XbbException {
        //1. 先拿到子表单数据
        List<UpdateDataEntity> subList = DataUtil.getUpdateSubDataList(list);
        // 2. 主表删掉子表单数据
        DataUtil.removeSubDataInData(subList);
        Integer integer = 0;
        if (CollectionsUtil.isNotEmpty(list)) {
            StandardizeDataUtil.standardizeList(list);
            integer = productDao.updateBatch(list, corpid);
            if(list.size()==1){
                paasEsModel.updateBySingle(list.get(0),IndexTypeEnum.IDX_SAAS_PRODUCT);
            }else {
                paasEsModel.updateBatchMuchField(list, IndexTypeEnum.IDX_SAAS_PRODUCT, refreshPolicy);
            }
        }

        if (!subList.isEmpty()) {
            productSubDataModel.updateBatch(subList, corpid);
        }
        return integer;
    }

    @Override
    public String getProductUnitTextByValue(String unitKey, FieldAttrEntity fieldAttrEntity) throws XbbException {
        if (StringUtil.isEmpty(unitKey) || fieldAttrEntity == null) {
            return null;
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(fieldAttrEntity.getAttr(), unitKey);
        Object value = ItemUtil.getCustomItemList(fieldAttrEntity, jsonObject);
        if (Objects.isNull(value)) {
            return null;
        }
        return value.toString();
//        String unitStr = "";
//        List<ItemPoJo> items = fieldAttrEntity.getItems();
//        boolean isOther = false;
//        if (items != null && !items.isEmpty()) {
//            for (ItemPoJo itemPoJo : items) {
//                String value = itemPoJo.getValue().toString();
//                if (value.equals(unitKey)) {
//                    return itemPoJo.getText();
//                }
//                if (Objects.equals(itemPoJo.getIsOther(),1)){
//                    isOther = true;
//                }
//            }
//        }
////        if (!ItemUtil.isUUID(unitKey) && !RegexUtil.isOnePositiveInt(unitKey)) {
////            unitStr = unitKey;
////        }
//        if (isOther){
//            return unitKey;
//        }
//        return unitStr;
    }

    @Override
    public Integer updateBatchSerialNo(List<UpdateDataEntity> list) throws XbbException {
        Integer result = productDao.updateBatchSerialNo(list);
        List<InsertDTO> insertList = new ArrayList<>();
        for (UpdateDataEntity item : list) {
            InsertDTO insertDTO = new InsertDTO();
            insertDTO.setEsId(item.getCorpid() + "_" + item.getId());
            Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            map.put(FieldTypeEnum.SERIALNO.getAlias(), item.getSerialNo());
            insertDTO.setSource(map);
            insertDTO.setIndexTypeEnum(IndexTypeEnum.IDX_SAAS_PRODUCT);
            insertList.add(insertDTO);
        }
        paasEsModel.updateBatch(insertList);
        return result;
    }

    @Override
    public List<AiProductEntity> getProductList4Ai(String corpid, List<Long> idIn) {
        return productDao.getProductList4Ai(corpid, idIn);
    }

    @Override
    public Integer updateBatch4JobNoEs(List<UpdateDataEntity> list, String corpid) throws XbbException {
        //1. 先拿到子表单数据
        List<UpdateDataEntity> subList = DataUtil.getUpdateSubDataList(list);
        // 2. 主表删掉子表单数据
        DataUtil.removeSubDataInData(list);
        StandardizeDataUtil.standardizeList(list);
        Integer integer = productDao.updateBatch(list, corpid);
        if (!subList.isEmpty()) {
            productSubDataModel.updateBatch(subList, corpid);
        }
        return integer;
    }

    @Override
    public List<String> getCorpidList() {
        return productDao.getCorpidList();
    }

    @Override
    public void updateStockDB(Set<Long> keySet, Collection<ProductStockUpdateEntity> values, String corpid) {
        productDao.updateStockDB(keySet,values,corpid);
        // 更新智能补货表中库存数量字段
        smartReplenishmentDao.updateStockDB(values,corpid);
    }

    @Override
    public void updateWarehouse(Set<Long> keySet, Map<Long, JSONObject> warehouseIdMap, String corpid) {
        if (keySet.isEmpty()){
            return;
        }
        productDao.updateWarehouse(keySet,warehouseIdMap,corpid);
    }

    @Override
    public void insertBatchFix(List<ProductEntityExt> productList, boolean dbInsert) throws XbbException{
        if (dbInsert) {
            for (ProductEntityExt entityExt : productList) {
                if (Objects.isNull(entityExt.getAddTime())) {
                    entityExt.setAddTime(DateTimeUtil.getInt());
                }
                if (Objects.isNull(entityExt.getUpdateTime())) {
                    entityExt.setUpdateTime(DateTimeUtil.getInt());
                }
            }
            StandardizeDataUtil.standardize4EntityList(productList);
            productDao.insertBatch(productList);
        } else {
            //ES数据插入
            List<InsertDTO> insertList = new ArrayList<>();
            for (ProductEntityExt entity : productList) {
                PaasFormDataEntity paasFormDataEntity = new PaasFormDataEntity();
                BeanUtil.copyProperties(entity, paasFormDataEntity);
                JSONObject data = paasFormDataEntity.getData();
                // 产品简介不入es
                data.put(ProductEnum.INSTRUCTION.getAttr(), "");
                paasFormDataEntity.setData(data);
                InsertDTO insertDTO = paasEsModel.getSaveDTO(paasFormDataEntity, IndexTypeEnum.IDX_SAAS_PRODUCT);
                insertDTO.setWaitUntil(WriteRequest.RefreshPolicy.NONE);
                insertList.add(insertDTO);
            }
            paasEsModel.insertBatch(insertList);
        }
        // todo 此处是脚本服务调用，暂不处理
    }

    /**
     * 将产品简介的es数据置空
     * @param list
     */
    private void setInstructionEmpty(List<UpdateDataEntity> list) {
        String instruction = StringConstant.JSON_DATA + StringConstant.POINT + ProductEnum.INSTRUCTION.getAttr();
        list.forEach(item->{
            item.getData().forEach(data->{
                if (Objects.equals(data.getEsKey(),  instruction)) {
                    data.setValue("");
                }
            });
        });
    }

    /**
     * 获取原父产品下的子产品，从es获取
     *
     * @param childProductDTO
     * @author chaoxiong.lei
     * @Date 21:29 2019/2/14
     * @since v1.0
     **/
    @Override
    public List<PaasFormDataEntityExt> getChildProductSimpleList(ChildProductDTO childProductDTO) throws XbbException {
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", childProductDTO.getCorpid()));
        boolQueryBuilder.filter(termsQuery(ProductEnum.getAttrConnectData(ProductEnum.PARENT_ID), childProductDTO.getParentProductId()));
        boolQueryBuilder.filter(termQuery(ParameterConstant.DEL, DelEnum.NORMAL.getDel()));
        if (Objects.equals(childProductDTO.getEnableSku(), 1)) {
            boolQueryBuilder.filter(termQuery(ProductEnum.getAttrConnectData(ProductEnum.ENABLE_SKU), 1));
        }
        XbbAggregatedPage<PaasFormDataEntityExt> byPage = esHelper.findByPage(IndexTypeEnum.IDX_SAAS_PRODUCT, boolQueryBuilder, ProductEntityExt.class, childProductDTO.getFieldList(), 0, 10000, Collections.singletonList(new FieldSortBuilder(BasicConstant.ID).order(SortOrder.ASC)));
        return byPage.getContent();
    }

    @Override
    public void formatUpdateExplain(FormatExplainDTO formatExplainDTO, JSONObject data) throws XbbException {
        // 将产品字段按照sort值排序
        //explainList.sort((FieldAttrEntity f1, FieldAttrEntity f2) -> f2.getSort() - f1.getSort());
        //编辑产品时多单位产品不允许编辑产品
        boolean enableMultiUnit = Objects.equals(data.getIntValue(ProductEnum.ENABLE_MULTI_UNIT.getAttr()), BasicConstant.ONE);
        String corpid = formatExplainDTO.getCorpid();
        FilterAttrOnOffJXCDTO filterAttrOnOffJXCDTO = new FilterAttrOnOffJXCDTO();
        BeanUtil.copyProperties(formatExplainDTO, filterAttrOnOffJXCDTO);
        filterAttrOnOffJXCDTO.setFieldAttrEntityList(formatExplainDTO.getExplainList());
        filterAttrOnOffJXCDTO.setOperatePageCode(OperatePageEnum.EDIT.getCode());
        filterAttrOnOffJXC(filterAttrOnOffJXCDTO);
        formatExplainDTO.setExplainList(filterAttrOnOffJXCDTO.getFieldAttrEntityList());
        for (FieldAttrEntity fieldAttrEntity : formatExplainDTO.getExplainList()) {
            if (Objects.equals(fieldAttrEntity.getAttr(), ProductEnum.STOCK_NOTIFY.getAttr())) {
                List<? extends FieldAttrEntity> subExplainList = fieldAttrEntity.getSubForm().getItems();
                for (FieldAttrEntity subField : subExplainList) {
                    subField.setEditable(fieldAttrEntity.getEditable());
                    subField.setEditableAdvanceEnable(fieldAttrEntity.getEditableAdvanceEnable());
                    subField.setEditableRule(fieldAttrEntity.getEditableRule());
                }
                fieldAttrEntity.getSubForm().setItems(subExplainList);
            }else if (Objects.equals(fieldAttrEntity.getAttr(), ProductEnum.UNIT.getAttr())) {
                ProductFieldPojo productFieldPojo = saasFormHelp.getProductFieldPojo(RedisPrefixConstant.PRODUCT_UNIT, ProductEnum.UNIT.getAttr(), corpid);
                fieldAttrEntity.setMultiItems(productFieldPojo.getMultiItems());
                if (enableMultiUnit && !formatExplainDTO.getFromCopy()) {
                    fieldAttrEntity.setEditable(0);
                }
            }else if (Objects.equals(fieldAttrEntity.getAttr(), ProductEnum.ENABLE_MULTI_UNIT.getAttr())){
                if (enableMultiUnit && !formatExplainDTO.getFromCopy()) {
                    fieldAttrEntity.setEditable(0);
                }
            }
        }
    }

    @Override
    public FilterAttrOnOffJXCVO filterAttrOnOffJXC(FilterAttrOnOffJXCDTO filterAttrOnOffJXCDTO) throws XbbException {
        FilterAttrOnOffJXCVO filterAttrOnOffJXCVO = new FilterAttrOnOffJXCVO();
        // 是否开启进销存
        Boolean enableJxc = filterAttrOnOffJXCDTO.getEnableJxc();
        Boolean isJxcUse = enableJxc;
        if (Objects.isNull(enableJxc)) {
            isJxcUse = paasAppModel.validateAppEnable(null, XbbRefTypeEnum.JXC.getAlias(), SaasMarkEnum.SAAS.getCode(), filterAttrOnOffJXCDTO.getCorpid());
        }
        List<FieldAttrEntity> headList = filterAttrOnOffJXCDTO.getFieldAttrEntityList();
        Integer operatePageCode = filterAttrOnOffJXCDTO.getOperatePageCode();
        if (!isJxcUse){
            // 进销存没有开启
            if (Objects.equals(operatePageCode, OperatePageEnum.DESIGN.getCode())) {
                headList.forEach(fieldAttrEntity -> {
                    if (productFilterAttrList.contains(fieldAttrEntity.getAttr())) {
                        fieldAttrEntity.setEditHide(1);
                    }
                });
            } else {
                headList.removeIf(fieldAttrEntity -> productFilterAttrList.contains(fieldAttrEntity.getAttr()));
            }
        } else {
            if (Objects.equals(operatePageCode, OperatePageEnum.DESIGN.getCode())) {
                Boolean batchShelf = companyConfigModel.getBatchShelf(filterAttrOnOffJXCDTO.getCorpid());
                Boolean seqManagement = companyConfigModel.getSeqManagement(filterAttrOnOffJXCDTO.getCorpid());
                for (FieldAttrEntity fieldAttrEntity : headList) {
                    if (noBatchSeqAttrList.contains(fieldAttrEntity.getAttr()) || (batchShelf && batchAttrList.contains(fieldAttrEntity.getAttr())) || (seqManagement && seqAttrList.contains(fieldAttrEntity.getAttr()))) {
                        fieldAttrEntity.setEditHide(0);
                    } else if (Objects.equals(fieldAttrEntity.getAttr(), ProductEnum.UNIT.getAttr())) {
                        // 只会走一次
                        ProductFieldPojo productFieldPojo = saasFormHelp.getProductFieldPojo(RedisPrefixConstant.PRODUCT_UNIT, ProductEnum.UNIT.getAttr(), filterAttrOnOffJXCDTO.getCorpid());
                        fieldAttrEntity.setMultiItems(productFieldPojo.getMultiItems());
                    }
                }
            } else {
                for (FieldAttrEntity fieldAttrEntity : headList) {
                    if ((Objects.equals(operatePageCode, OperatePageEnum.LIST.getCode()) || Objects.equals(operatePageCode, OperatePageEnum.DETAIL.getCode())) && Objects.equals(fieldAttrEntity.getAttr(), ProductEnum.UNIT.getAttr())) {
                        fieldAttrEntity.setItems(saasFormHelp.getProductItems(filterAttrOnOffJXCDTO.getCorpid()));
                    }
                }
            }
        }
        return filterAttrOnOffJXCVO;
    }



    @Override
    public String getPriceOrCostRegion(List<PaasFormDataEntityExt> childProductList, String attr, Integer accuracy) throws XbbException {
        if (Objects.isNull(accuracy)) {
            accuracy = AttrDecimalPrecisionHelper.DEFAULT_PRECISION;
        }
        PaasFormDataEntityExt minProduct = childProductList.stream().min(Comparator.comparing(item -> item.getData().getDouble(attr))).orElse(null);
        Double lowPriceStr = 0D;
        if (minProduct != null) {
            lowPriceStr = getDoubleOrDefaultFromFormData(minProduct.getData(), attr, 0D);
        }
        PaasFormDataEntityExt maxProduct = childProductList.stream().max(Comparator.comparing(item -> item.getData().getDouble(attr))).orElse(null);
        Double highPriceStr = 0D;
        if (maxProduct != null) {
            highPriceStr = getDoubleOrDefaultFromFormData(maxProduct.getData(), attr, 0D);
        }
        if (Objects.equals(Double.compare(lowPriceStr, highPriceStr), 0)) {
            return new BigDecimal(lowPriceStr).setScale(accuracy, BigDecimal.ROUND_HALF_UP).toPlainString();
        } else {
            String lowPrice = new BigDecimal(lowPriceStr).setScale(accuracy, BigDecimal.ROUND_HALF_UP).toPlainString();
            String highPrice = new BigDecimal(highPriceStr).setScale(accuracy, BigDecimal.ROUND_HALF_UP).toPlainString();
            return String.format(StringConstant.PRICE_RANFE, lowPrice, highPrice);
        }
    }

    /**
     *
     * 处理多单位产品单位和价格对不上的情况
     * @param unitItemPoJos
     * @param price
     */
    @Override
    public JSONArray formatMultiPrice(List<UnitItemPoJo> unitItemPoJos, JSONArray price) {
        List<MultiUnitPricePoJo> multiUnitPricePoJos = formatMultiPrice(price, unitItemPoJos);
        return JSONArray.parseArray(JSON.toJSONString(multiUnitPricePoJos));
    }

    public static List<MultiUnitPricePoJo> formatMultiPrice(JSONArray price, List<UnitItemPoJo> unitItemPoJos) {
        unitItemPoJos = unitItemPoJos == null ? new ArrayList<>() : unitItemPoJos;
        List<MultiUnitPricePoJo> multiUnitPricePoJos = price.toJavaList(MultiUnitPricePoJo.class);
        multiUnitPricePoJos = multiUnitPricePoJos == null ? new ArrayList<>() : multiUnitPricePoJos;
        if (unitItemPoJos.size() != multiUnitPricePoJos.size()) {
            List<Long> priceUnitIds = new ArrayList<>();
            multiUnitPricePoJos.forEach(item->priceUnitIds.add(item.getValue()));
            for (UnitItemPoJo itemPoJo : unitItemPoJos) {
                if (!priceUnitIds.contains(itemPoJo.getValue())) {
                    MultiUnitPricePoJo multiUnitPricePoJo = new MultiUnitPricePoJo();
                    multiUnitPricePoJo.setValue(itemPoJo.getValue());
                    multiUnitPricePoJo.setText(itemPoJo.getText());
                    multiUnitPricePoJo.setRate(0D);
                    multiUnitPricePoJos.add(multiUnitPricePoJo);
                }
            }
        }
        return multiUnitPricePoJos;
    }

    @Override
    public void formatData(SaasAnalysisDataDTO saasAnalysisDataDTO, JSONObject result) throws XbbException {
        showFormatHelp.format4Show(saasAnalysisDataDTO, result);
    }

    @Override
    public Map<Long, ProductEntityExt> getProductMap(String corpid, JSONArray productArray) {
        List<Long> productIdIn = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (int i = 0; i < productArray.size(); i++) {
            JSONObject object = productArray.getJSONObject(i);
            // 页面传入的产品的id
            Long productId = object.getLong(StringConstant.SAAS_LINK_BUSINESS_ID);
            productIdIn.add(productId);
        }
        // 获取产品信息
        Map<Long, ProductEntityExt> productMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (productIdIn.size() >= 1) {
            // 从产品表中获取对应的产品信息
            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("corpid", corpid);
            params.put("idIn", productIdIn);
            params.put("del", 0);
            List<ProductEntityExt> productModelEntitys = findEntitys(params);
            if (productModelEntitys != null) {
                for (ProductEntityExt entity : productModelEntitys) {
                    productMap.put(entity.getId(), entity);
                }
            }
        }
        return productMap;
    }

    @Override
    public Map<Long, ProductEntityExt> getProductMap(Set<Long> productIdList, String corpid, JSONArray productArray) {
        List<Long> productIdIn = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (int i = 0; i < productArray.size(); i++) {
            JSONObject object = productArray.getJSONObject(i);
            // 页面传入的产品的id
            Long productId = object.getLong(StringConstant.SAAS_LINK_BUSINESS_ID);
            productIdIn.add(productId);
            productIdList.add(productId);
        }
        // 获取产品信息
        Map<Long, ProductEntityExt> productMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (productIdIn.size() >= 1) {
            // 从产品表中获取对应的产品信息
            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("corpid", corpid);
            params.put("idIn", productIdIn);
            params.put("del", 0);
            List<ProductEntityExt> productModelEntitys = findEntitys(params);
            if (productModelEntitys != null) {
                for (ProductEntityExt entity : productModelEntitys) {
                    productMap.put(entity.getId(), entity);
                }
            }
        }
        return productMap;
    }

    @Override
    public Map<String, PriceProductSetEntity> getPriceMap(String corpid, Long refId, Long formId, List<Long> productIdIn, Map<Long, Boolean> multiUnitMap) throws XbbException{
        Map<String, PriceProductSetEntity> priorityMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // TODO 1.先筛选出符合经销商id 主表数据 2.时间+rules 筛选出符合的价目表idIn  3.从表 priceIdIn + productIdIn的价目表 + 优先级  3 封装price 和sellingPriceMap
        CustomerEntityExt customerEntityExt = customerModel.getByKey(refId, corpid);
        if (Objects.isNull(customerEntityExt)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, I18nMessageUtil.getMessage(MessageConstant.FORM_DATA_NOT_EXIST));
        }
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(ParameterConstant.CORPID, corpid);
        param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        param.put(ParameterConstant.ENABLE, 1);
        param.put("formId", customerEntityExt.getFormId());
        //该公司下 所有价目表
        List<PriceSetEntity> priceSetEntityList = priceSetModel.findEntitys(param);
        Long now = DateTimeUtil.getInt();
        //过滤掉不符合时间的价目表
        priceSetEntityList.removeIf(PriceSetEntity -> (Objects.nonNull(PriceSetEntity.getStartTime()) && now < PriceSetEntity.getStartTime()) || (Objects.nonNull(PriceSetEntity.getEndTime()) && now > PriceSetEntity.getEndTime()));

        List<ProductPriceSetPOJO> matchList = new ArrayList<>();
        JSONObject data = customerEntityExt.getData();
        // 查询负责团队
        List<String> customerUserIdList = customerUserModel.getCustomerUserIdList(corpid, Arrays.asList(refId), 1);
        if (CollectionsUtil.isNotEmpty(customerUserIdList)) {
            data.put(TabConstant.OWNERID, customerUserIdList);
        }
        List<String> addressAttrList = Arrays.asList("province", "city", "district", "address");
        Outer:
        for (PriceSetEntity priceSetEntity : priceSetEntityList) {
            if (Objects.equals(priceSetEntity.getAdapterType() ,BasicConstant.ZERO)) {
                matchList.add(new ProductPriceSetPOJO(priceSetEntity.getId(), priceSetEntity.getPriority(), priceSetEntity.getStartTime(), priceSetEntity.getEndTime()));
                continue;
            }
            List<ConditionsEntityExt> conditionsEntityExts = priceSetEntity.getRule().toJavaList(ConditionsEntityExt.class);
            for (ConditionsEntityExt conditionsEntityExt : conditionsEntityExts) {
                String attr = conditionsEntityExt.getAttr();
                List<Object> value = conditionsEntityExt.getValue();
                //过滤地址不符合的价目表
                if (addressAttrList.contains(conditionsEntityExt.getAttr())) {
                    if (Objects.isNull(data.getJSONObject(CustomerManagementEnum.ADDRESS.getAttr())) || Objects.isNull(value) || value.isEmpty()
                            || !Objects.equals(data.getJSONObject(CustomerManagementEnum.ADDRESS.getAttr()).getString(conditionsEntityExt.getAttr()), value.get(0).toString())) {
                        continue Outer;
                    }
                } else if (Objects.equals(conditionsEntityExt.getFieldType(), FieldTypeEnum.SERIALNO.getType())) {
                    data.put(FieldTypeEnum.SERIALNO.getAlias(), customerEntityExt.getSerialNo());
                    if (!webCommonDataValueMatchHandle.match(conditionsEntityExt, data)) {
                        continue Outer;
                    }
                } else {
                    Object dataValue = data.get(attr);
                    if (dataValue instanceof List) {
                        if (!webListDataValueMatchHandle.match(conditionsEntityExt, data)) {
                            continue Outer;
                        }
                    } else {
                        if (!webCommonDataValueMatchHandle.match(conditionsEntityExt, data)) {
                            continue Outer;
                        }
                    }
                }
            }
            matchList.add(new ProductPriceSetPOJO(priceSetEntity.getId(), priceSetEntity.getPriority(), priceSetEntity.getStartTime(), priceSetEntity.getEndTime()));
        }
        if (matchList.isEmpty()) {
            return priorityMap;
        }
        //价目表id list
        Set<Long> priceSetIdSet = new HashSet<>();
        Map<Long, Integer> priceLevelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (ProductPriceSetPOJO productPriceSetPOJO : matchList) {
            priceSetIdSet.add(productPriceSetPOJO.getId());
            priceLevelMap.put(productPriceSetPOJO.getId(), productPriceSetPOJO.getPriority());
        }
        Map<String, Object> productParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        productParam.put(ParameterConstant.CORPID, corpid);
        productParam.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        productParam.put("productIdIn", productIdIn);
        productParam.put("priceIdIn", priceSetIdSet);
        List<PriceProductSetEntity> productList = priceProductSetModel.findEntitys(productParam);
        if (productList.isEmpty()) {
            return priorityMap;
        }
        // 获取价目表的价格set
        productList.forEach(item -> {
            Long productId = item.getProductId();
            String key = productId.toString();
            if (multiUnitMap.get(productId)) {
                key = productId + SymbolConstant.UNDERLINE + item.getProductUnit();
            }
            if (!priorityMap.containsKey(key) || priceLevelMap.get(priorityMap.get(key).getPriceId()) > priceLevelMap.get(item.getPriceId())) {
                priorityMap.put(key, item);
            }
        });
        return priorityMap;
    }

    /**
     * 根据productIdIn获取对应产品信息,需要分页信息，从es中获取
     * @param productIds
     * @param corpid
     * @param delEnum
     * @return
     * @throws XbbException
     */
    @Override
    public List<PaasFormDataEntityExt> getProductListById(Set<Long> productIds, String corpid, DelEnum delEnum) throws XbbException {
        // 根据productIdIn获取对应产品信息，需要分页信息，从es中获取
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termsQuery("dataId",productIds));
        if (!Objects.isNull(delEnum)){
            boolQueryBuilder.filter(termQuery(StringConstant.DEL,delEnum.getDel()));
        }
        List<String> fieldList = new ArrayList<>();
        fieldList.add(StringConstant.DATA_ID);
        fieldList.add(FieldTypeEnum.SERIALNO.getAlias());
        fieldList.add(StringConstant.JSON_DATA);
        return esHelper.findByPage(IndexTypeEnum.IDX_SAAS_PRODUCT,boolQueryBuilder,PaasFormDataEntityExt.class,fieldList, 1, productIds.size(), null).getContent();
    }

    @Override
    public void updateProductCostByid(List<ProductEntityExt> productEntityExtList , String corpid){
        StandardizeDataUtil.standardize4EntityList(productEntityExtList);
        productDao.updateProductCostByid(productEntityExtList , corpid);
    }

    @Override
    public List<ProductEntityExt> getCostIsNullProduct(String corpid){
        return productDao.getCostIsNullProduct(corpid);
    }

    @Override
    public Integer saveNoSubForm(ProductEntityExt productEntityExt) throws XbbException{
        if (Objects.isNull(productEntityExt.getId()) || Objects.equals(0L, productEntityExt.getId()) ) {
            return insertNoSubForm(productEntityExt);
        }
        return updateNoSubForm(productEntityExt);
    }

    @Override
    public Integer insertNoSubForm(ProductEntityExt entity) throws XbbException{
        paasFormSubDataModel.transferSubForm(entity, IndexTypeEnum.IDX_SAAS_PRODUCT_SUB);
        StringStreamUtil.validateDataSize(JSON.toJSONString(entity.getData()));
        StandardizeDataUtil.standardizeNotString(entity);
        Integer insertId = productDao.insert(entity);
        PaasFormDataEntity paasFormDataEntity = new PaasFormDataEntity();
        BeanUtil.copyProperties(entity, paasFormDataEntity);
        JSONObject data = paasFormDataEntity.getData();
        // 产品简介不入es
        data.put(ProductEnum.INSTRUCTION.getAttr(),"");
        paasFormDataEntity.setData(data);
        InsertDTO insertDTO = paasEsModel.getSaveDTO(paasFormDataEntity, IndexTypeEnum.IDX_SAAS_PRODUCT);
        insertDTO.getSource().remove("num");
        insertDTO.getSource().remove("cost");
        insertDTO.getSource().remove("totalCost");
        paasEsModel.insert(insertDTO);
        return insertId;
    }

    @Override
    public Integer updateNoSubForm(ProductEntityExt entity) throws XbbException{
        long now = DateTimeUtil.getInt();
        entity.setUpdateTime(now);

        paasFormSubDataModel.transferSubForm(entity, IndexTypeEnum.IDX_SAAS_PRODUCT_SUB);
        StringStreamUtil.validateDataSize(JSON.toJSONString(entity.getData()));
        StandardizeDataUtil.standardizeNotString(entity);
        Integer updateId = productDao.update(entity);
        PaasFormDataEntity paasFormDataEntity = new PaasFormDataEntity();
        BeanUtil.copyProperties(entity, paasFormDataEntity);
        JSONObject data = paasFormDataEntity.getData();
        // 产品简介不入es
        data.put(ProductEnum.INSTRUCTION.getAttr(),"");
        paasFormDataEntity.setData(data);
        InsertDTO insertDTO = paasEsModel.getSaveDTO(paasFormDataEntity, IndexTypeEnum.IDX_SAAS_PRODUCT);
        insertDTO.getSource().remove("num");
        insertDTO.getSource().remove("cost");
        insertDTO.getSource().remove("totalCost");
        paasEsModel.update(insertDTO);
        return updateId;
    }

    @Override
    public Map<Long, PaasFormDataEntityExt> getProductSpecificationMap(Collection productIdSet, String corpid) throws XbbException {
        Map<Long,PaasFormDataEntityExt> productMap = new HashMap<>();
        //获取关联字段
        //获取产品数据，最多200条
        if (!productIdSet.isEmpty()){
            BoolQueryBuilder boolQueryBuilder = boolQuery();
            boolQueryBuilder.filter(termQuery("corpid.keyword",corpid))
                    .filter(termsQuery(FieldTypeEnum.DATAID.getAlias(),productIdSet));
            SearchRequest searchRequest = EsUtil.simplePackageForQueryForPage(IndexTypeEnum.IDX_SAAS_PRODUCT,boolQueryBuilder,null,0, productIdSet.size());
            XbbAggregatedPage<PaasFormDataEntityExt> result = xbbElasticsearchRestTemplate.queryForPages(searchRequest,PaasFormDataEntityExt.class);
            List<PaasFormDataEntityExt> productList = result.getContent();
            formDataHelp.setChildSpecification(productList,corpid);
            for (PaasFormDataEntityExt entityExt : productList) {
                productMap.put(entityExt.getDataId(),entityExt);
            }
        }
        return productMap;
    }

    @Override
    public List<PaasFormDataEntityExt> getChildProductList(ChildProductDTO childProductDTO) throws XbbException {
        // 这里之前实现的是com.xbongbong.parent.data.FormDataEsServiceImpl.getChildProductList
        // 然而在调用中无需那么复杂的调用，所以此处重写简化代码
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        String corpid = childProductDTO.getCorpid();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid))
                .filter(termQuery("del", DelEnum.NORMAL.getDel()))
                .filter(termsQuery(ProductEnum.getAttrConnectData(ProductEnum.PARENT_ID), childProductDTO.getParentProductId()));
        Long count = paasEsModel.count(boolQueryBuilder, IndexTypeEnum.IDX_SAAS_PRODUCT);
        childProductDTO.setPageSize(count.intValue());
        return paasEsModel.getDataList(boolQueryBuilder, IndexTypeEnum.IDX_SAAS_PRODUCT, null, 1, childProductDTO.getPageSize(), PaasFormDataEntityExt.class, FieldTypeEnum.ADDTIME.getAlias(), SortOrder.ASC);
    }

    /**
     * 关联数据是产品时，需要返回如下属性
     * @param targetData
     * @return
     */
    public static JSONObject setProductAttribute(JSONObject targetData) {
        JSONObject valueJson = new JSONObject();
        valueJson.put(ProductEnum.ENABLE_SERIAL_NUMBER.getSaasAttr(), targetData.get(ProductEnum.ENABLE_SERIAL_NUMBER.getAttr()));
        Integer enableShelfLife = StringUtil.isEmpty(targetData.getString(ProductEnum.SHELF_LIFE_DAYS.getAttr())) ? 0 : 1;
        valueJson.put(ProductEnum.ENABLE_BATCH_SHELF_LIFE.getSaasAttr(), targetData.get(ProductEnum.ENABLE_BATCH_SHELF_LIFE.getAttr()));
        valueJson.put(ProductEnum.UNIT.getSaasAttr(), targetData.get(ProductEnum.UNIT.getAttr()));
        valueJson.put(ProductEnum.SHELF_LIFE_DAYS.getSaasAttr(), enableShelfLife);
        valueJson.put(ProductEnum.ENABLE_MULTI_UNIT.getSaasAttr(), Objects.isNull(targetData.getLong(ProductEnum.ENABLE_MULTI_UNIT.getAttr())) ? 0: targetData.getLong(ProductEnum.ENABLE_MULTI_UNIT.getAttr()));
        return valueJson;
    }
    @Override
    public Long getParentDataId(Long dataId, Integer businessType, String corpid) {
        if(Objects.equals(businessType, XbbRefTypeEnum.PRODUCT.getCode())){
            Map<String, Object> param = new HashMap<>(4);
            param.put("corpid", corpid);
            param.put("id", dataId);
            param.put("del", DelEnum.NORMAL.getDel());
            param.put("columns","id,corpid,data");
            List<ProductEntityExt> productList = findEntitysWithoutSub(param);
            if(CollectionUtils.isNotEmpty(productList)){
                dataId = productList.get(0).getData().getLong(ProductEnum.PARENT_ID.getAttr());
            }
        }
        return dataId;
    }
}
